﻿// Decompiled with JetBrains decompiler
// Type: Netick.OnChangedData
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System;
using System.Runtime.CompilerServices;

#nullable disable
namespace Netick;

public struct OnChangedData : IEquatable<OnChangedData>
{
  internal OnChangedEvent Event;
  internal INetickNetworkScript Behaviour;
  internal int InversePrecision;
  internal int IsServer;
  internal unsafe int* PreviousValue;
  internal int Offset;
  internal int PropertyIndex;
  internal int SizeWords;

  internal unsafe OnChangedData(
    int propertyIndex,
    int isServer,
    int* previousValue,
    OnChangedEvent evnt,
    int offset,
    int sizeWords,
    int inversePrecision,
    INetickNetworkScript networkBehaviour = null)
  {
    this.PropertyIndex = propertyIndex;
    this.IsServer = isServer;
    this.PreviousValue = previousValue;
    this.Event = evnt;
    this.Offset = offset;
    this.SizeWords = sizeWords;
    this.Behaviour = networkBehaviour;
    this.InversePrecision = inversePrecision;
  }

  /// <summary>
  /// Returns true if this OnChanged callback is due to a mismatch between the state of this variable before rollback, and the state after rollback and resimulation.
  /// </summary>
  public bool InvokedForMisprediction => this.IsServer == 1;

  /// <summary>
  /// Gets a snapshot of the previous state of a NetworkDictionary collection.
  /// </summary>
  /// <returns></returns>
  public unsafe NetworkDictionarySnapshot<TKey, TValue> GetPreviousNetworkDictionary<TKey, TValue>(
    NetworkDictionary<TKey, TValue> collection)
    where TKey : unmanaged
    where TValue : unmanaged
  {
    return new NetworkDictionarySnapshot<TKey, TValue>(this.PreviousValue, collection._length);
  }

  /// <summary>
  /// Gets a snapshot of the previous state of a NetworkHashSet collection.
  /// </summary>
  /// <returns></returns>
  public unsafe NetworkHashSetSnapshot<T> GetPreviousNetworkHashSet<T>(NetworkHashSet<T> collection) where T : unmanaged
  {
    return new NetworkHashSetSnapshot<T>(this.PreviousValue, collection._length);
  }

  /// <summary>
  /// Gets a snapshot of the previous state of a NetworkLinkedList collection.
  /// </summary>
  /// <returns></returns>
  public unsafe NetworkLinkedListSnapshot<T> GetPreviousNetworkLinkedList<T>(
    NetworkLinkedList<T> collection)
    where T : unmanaged
  {
    return new NetworkLinkedListSnapshot<T>(this.PreviousValue);
  }

  /// <summary>
  /// Gets a snapshot of the previous state of a NetworkUnorderedList collection.
  /// </summary>
  /// <returns></returns>
  public unsafe NetworkUnorderedListSnapshot<T> GetPreviousNetworkUnorderedList<T>(
    NetworkUnorderedList<T> collection)
    where T : unmanaged
  {
    return new NetworkUnorderedListSnapshot<T>(this.PreviousValue);
  }

  /// <summary>
  /// Gets a snapshot of the previous state of a NetworkQueue collection.
  /// </summary>
  /// <returns></returns>
  public unsafe NetworkQueueSnapshot<T> GetPreviousNetworkQueue<T>(NetworkQueue<T> collection) where T : unmanaged
  {
    return new NetworkQueueSnapshot<T>(this.PreviousValue, collection._length);
  }

  /// <summary>
  /// Gets a snapshot of the previous state of a NetworkStack collection.
  /// </summary>
  /// <returns></returns>
  public unsafe NetworkStackSnapshot<T> GetPreviousNetworkStack<T>(NetworkStack<T> collection) where T : unmanaged
  {
    return new NetworkStackSnapshot<T>(this.PreviousValue);
  }

  /// <summary>
  /// Gets previous value for the changed network property.
  /// <para>Note: this must only be used with non-array network properties. For arrays, use <see cref="M:Netick.OnChangedData.GetArrayPreviousElementValue``1(System.Int32)" /> instead. </para>
  /// </summary>
  /// <typeparam name="T"></typeparam>
  /// <returns></returns>
  public unsafe T GetPreviousValue<T>() where T : unmanaged
  {
    if (this.InversePrecision == -1)
      return *(T*) this.PreviousValue;
    T previousValue = default (T);
    float* numPtr = (float*) &previousValue;
    float num = 1f / (float) this.InversePrecision;
    for (int index = 0; index < this.SizeWords; ++index)
      numPtr[index] = (float) this.PreviousValue[index] * num;
    return previousValue;
  }

  /// <summary>Gets a pointer to the previous value</summary>
  /// <returns></returns>
  public unsafe int* GetPreviousValueAsPointer() => this.PreviousValue;

  /// <summary>Gets the index of the changed element of the array.</summary>
  /// <returns></returns>
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public int GetArrayChangedElementIndex() => this.Offset;

  /// <summary>
  /// Gets the value of the changed element of the array. This is an unsafe method, use it carefully and make sure to never go outside range to avoid a crash.
  /// </summary>
  /// <returns></returns>
  public unsafe T GetArrayPreviousElementValue<T>(int index) where T : unmanaged
  {
    return *(T*) (this.PreviousValue + index * this.SizeWords);
  }

  /// <summary>Gets the index of the changed element of the array.</summary>
  /// <typeparam name="T"></typeparam>
  /// <returns></returns>
  public T GetArrayPreviousElementValue<T>() where T : unmanaged
  {
    return this.GetArrayPreviousElementValue<T>(this.GetArrayChangedElementIndex());
  }

  public override bool Equals(object obj) => obj is OnChangedData other && this.Equals(other);

  public unsafe bool Equals(OnChangedData other)
  {
    return this.Event == other.Event && this.Offset == other.Offset && this.PreviousValue == other.PreviousValue;
  }

  public override unsafe int GetHashCode()
  {
    return (this.Event, this.Offset, (ulong) this.PreviousValue).GetHashCode();
  }
}
